const http = require('http');
const Redis = require('ioredis');
const config = require('./config');

const App = require('./app');
const redis = new Redis(config.redis);
redis.defineCommand("ratelimit", {
  numberOfKeys: 1,
  lua: `
    local banned = redis.call('EXISTS', 'b'..KEYS[1])

    if banned == 1
      then
        return -1
    end

    local res = redis.call('SET', 'c'..KEYS[1], ${config.rate.numOfRequests}, 'NX','EX', ${config.rate.interval})

    if res==false
    then
        local val = redis.call('DECRBY', 'c'..KEYS[1], 1)
        if val <= 0 then
          redis.call('SET', 'b'..KEYS[1], 1, 'NX', 'EX', ${config.rate.timeout})
          return -1;
        end
    end

    return 1
  `,
});

const app = App(redis);

const server = http.createServer(app);

server.once('error', (err) => {
  console.log('Failed to start server: %s', err);
  cleanup();
  process.exit(1);
});

const cleanup = () => {
  redis.disconnect()
  server.close();
};

process
  .once("SIGINT", async () => {
    console.log("SIGINT received");
    cleanup();
  })
  .once("SIGTERM", async () => {
    console.log("SIGTERM received");
    cleanup();
  })
  .on('unhandledRejection', async (reason, p) => {
    console.error(reason, 'Unhandled Rejection at Promise', p);
  })
  .on('uncaughtException', async (err) => {
    console.error('Uncaught Exception thrown', err);
    cleanup();
    process.exit(1);
  });

void async function start () {
  const listener = server.listen(config.app.port, (data) => {
    console.log('Server started on port: %d', listener.address().port);
  });
}();
